#include "NewView.hpp"

using namespace BFT::order::messages;

NewView::NewView(uint32_t _view, std::vector<boost::shared_ptr<BFT::messages::Digest> > _chosenvcs, 
		 uint32_t _sendingReplica, int _k)
	: BFT::messages::MacArrayMessage::MacArrayMessage(NEW_VIEW, computeSize(_chosenvcs, _k), 
					_sendingReplica, BFT::Parameters::getOrderCount())
{
	viewNo = _view;
	chosenVCs = _chosenvcs;
	
	int offset = getOffset();
	int bytes_size;
	boost::shared_ptr<char> bytes = getBytes(bytes_size);
	
	//write down the view number
	*(uint32_t*)(bytes.get() + offset) = htonl(viewNo);
	offset += VIEW_NUMBER_SIZE;
	
	//write down the ViewChange digests
	for(unsigned int j = 0 ; j < chosenVCs.size(); j++)
	{
		if(chosenVCs.at(j).use_count() > 0)
		{
			//write down the index of the replica that sent the VC (j)
			*(uint32_t*)(bytes.get() + offset) = htonl(j);
			offset += SENDER_SIZE;
			
			//write down the digest
			memcpy( (void*)( bytes.get() + offset) , (const void*)( chosenVCs.at(j).get()->getBytes().get() ) 
			        , DIGEST_SIZE );
			offset += DIGEST_SIZE;
		}
	}
}

//k is the number of non-null entrues in chosenvcs
//n is the total size of the said arary
NewView::NewView(boost::shared_ptr<char> _bytes, int _bytes_size, int _k, int _n)
	: BFT::messages::MacArrayMessage::MacArrayMessage(_bytes, _bytes_size)
{
	if(getTag()!=NEW_VIEW)
	{
		fprintf(stderr,"NewView::NewView says trying to build a newview from bytes with wrong tag!\n");
		exit(161);
	}
	
	int offset = getOffset();
	
	//read the view number
	viewNo = ntohl( *(uint32_t*)(_bytes.get()+offset) );
	offset += SEQUENCE_NUMBER_SIZE;
	
	//read the chosen vcs
	chosenVCs.resize(_n); //isn't it the number of order replicas?
	boost::shared_ptr<char> temp_bytes ((char*)malloc(DIGEST_SIZE));
	uint32_t sender;
	
	for(int j=0; j<_k ;j++)
	{
		//read the sender
		sender = ntohl( *(uint32_t*)(_bytes.get()+offset) );
		offset += SENDER_SIZE;
		
		//read the vc hash bytes
		memcpy((void*)(temp_bytes.get()) , (const void*)(_bytes.get()+offset) , DIGEST_SIZE );
		offset += DIGEST_SIZE;
		
		//create the hash from bytes and assign to the right place in chosenVCs
		chosenVCs.at(sender).reset( new BFT::messages::Digest(temp_bytes, DIGEST_SIZE));
	}
	
	if((unsigned int) offset != _bytes_size - getAuthenticationSize())
	{
		fprintf(stderr,"NewView::NewView says: trying to build a NewView from invalid bytes\n");
		exit(162);
	}
}


//Assuming that n is the number of order replicas
//the vaule of k is computed using the size of the message

NewView::NewView(boost::shared_ptr<char> _bytes, int _bytes_size)
	: BFT::messages::MacArrayMessage::MacArrayMessage(_bytes, _bytes_size)
{
	if(getTag()!=NEW_VIEW)
	{
		fprintf(stderr,"NewView::NewView says trying to build a newview from bytes with wrong tag!\n");
		exit(161);
	}
	
	int offset = getOffset();
	
	//read the view number
	viewNo = ntohl( *(uint32_t*)(_bytes.get()+offset));
	offset += SEQUENCE_NUMBER_SIZE;
	
	//read the chosen vcs
	chosenVCs.resize(BFT::Parameters::getOrderCount()); //isn't it the number of order replicas?
	boost::shared_ptr<char> temp_bytes ((char*)malloc(DIGEST_SIZE));
	uint32_t sender;
	
	//compute the number of entries to be read
	int remaining_size = (_bytes_size - getAuthenticationSize()) - offset;
	int _k = (remaining_size / (SENDER_SIZE + DIGEST_SIZE));
//	fprintf(stderr," ********  computed _k = %d  ********\n",_k);
	for(int j=0; j<_k ;j++)
	{
		//read the sender
		sender = ntohl( *(uint32_t*)(_bytes.get()+offset));
		offset += SENDER_SIZE;

//		fprintf(stderr," ******** sender = %d  ********\n",sender);

		//read the vc hash bytes
		memcpy((void*)(temp_bytes.get()) , (const void*)(_bytes.get()+offset) , DIGEST_SIZE );
		offset += DIGEST_SIZE;
		
		//create the hash from bytes and assign to the right place in chosenVCs
		chosenVCs.at(sender).reset( new BFT::messages::Digest(temp_bytes, DIGEST_SIZE));
	}
	
	if((unsigned int) offset != _bytes_size - getAuthenticationSize())
	{
		fprintf(stderr,"NewView::NewView says: trying to build a NewView from invalid bytes\n");
		exit(162);
	}
}


bool NewView::equals(boost::shared_ptr<NewView> _other_nv)
{
	bool equal = BFT::messages::MacArrayMessage::equals(_other_nv) && viewNo == _other_nv.get()->getView();
	
	if(!equal)
		return false;
	
	std::vector<boost::shared_ptr<BFT::messages::Digest> > _other_cvcs = _other_nv.get()->getChosenVCs();
	
	equal = equal && chosenVCs.size()==_other_cvcs.size();
		
	for(unsigned int i=0; i<chosenVCs.size() && equal; i++)
	{
		if(chosenVCs.at(i).use_count() == 0)
		{
			equal = _other_cvcs.at(i).use_count() == 0;
		}
		else
		{
			equal = chosenVCs.at(i).get()->equals( _other_cvcs.at(i) ); 
		}
	}
	
	return equal;
}

uint32_t NewView::computeSize(std::vector<boost::shared_ptr<BFT::messages::Digest> > _vcs, int _k)
{
	return VIEW_NUMBER_SIZE + _k*(SENDER_SIZE + DIGEST_SIZE);
}
